//5-3constructorparam.ts
// 2. 获取构造函数的参数
class TestClass {
  // 准备类
  public name: string
  public classno: number
  constructor(name: string, classno: number) {
    this.name = name
    this.classno = classno
  }
  eat() {
    console.log('姓名为: ' + this.name)
  }
}

// s100
type ConstructorParametersType1<T> = T extends new (...args: infer P) => any
  ? P
  : never

/**
 *  这里鼠标发过去是一个元组 let constructorParameters: [name: string, classno: number]
 *  也就是将 TestClass 构造函数的 name classno 直接拿出来了 以元组的形式放到 P当中，所以 P最终返回元组类型
 *  typeof TestClass 表示的是构造函数的类型
 * typeof TestClass 等于 new (name: string, classno: number) => TestClass 就传递给 T
 * s100 等于 s101
 */
// s101
type ConstructorParametersType2<T extends new (...args: any[]) => any> =
  T extends new (...args: infer P) => any ? P : never
//  获取到了 TestClass 构造函数的参数类型 放到一个元组中[name: string, classno: number]
// let constructorParameters:
//     ConstructorParametersType<new (name: string, classno: number) => TestClass> 同下意思相同
let constructorParameters: ConstructorParametersType1<typeof TestClass>
/**
 * TestClass 类有双重性质 1.代表构造函数对象变量 2.直接 new 的时候是类型
 * new TestClass() 此时是一种类型 他和构造器 new (...args: any[]) => T 的类型是不是同一种呢？ 不是
 * 当直接 new 的时候是拿构造函数对象变量， 构造器的类型指的是对象空间的类型
 */

/**
 * 此时还会存在问题，当传递错误的时候是没有任何提示的 例如传递一个 string 也没有任何提示
 * 限定 T 的类型即可 T extends new (...args: any[]) => any 演变为构造器类型
 *
 */

type ConstructorParametersType3<T extends new (...args: any[]) => any> =
  T extends new (...args: infer P) => any ? P : never
let constructorParameters2: ConstructorParametersType3<typeof TestClass>

type Constructor<T> = new (...args: any[]) => T // 构造函数类型的通用类型

export {}
